namespace WPFBPMN
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using CustomControls;
    using Utils;

    public partial class WindowMain : System.Windows.Window
    {
        #region Fields
        public static bool WaitingForUserInteraction = false;
        static BPMNShape selectedBPMNShape = null;
        public static WPFBPMN.Utils.ShapeType DrawingToBuild = ShapeType.BPMNEventStart;
        public static List<string> AdditionalParameters = new List<string>();
        static BPMNConnectingObject BPMNConnectingObject;
        public string path = @"C:\Documents and Settings\mihai mihaila\Desktop\bpmn\bpmn\WPFBPMN\WPFBPMN";
        BPMNExpander bpmnExpanderStartEvents;
        BPMNExpander bpmnExpanderIntermediateEvents;
        BPMNExpander bpmnExpanderEndEvents;
        BPMNExpander bpmnExpanderGateways;
        BPMNExpander bpmnExpanderConnectingObjects;
        BPMNExpander bpmnExpanderBasicShapes;
        BPMNShape canvas;
        #endregion

        #region Properties

        public static BPMNShape SelectedBPMNShape
        {
            get
            {
                return selectedBPMNShape;
            }
            set
            {
                selectedBPMNShape = value;
                Commons.Utils.PopulateProperties(value);
            }
        }
        #endregion

        public WindowMain()
        {
            InitializeComponent();
            BPMNInitialize();
        }

        private void InitializeCanvas()
        {
            canvas = new BPMNShape(null);
            canvas.ShapeDefaultSize = new Size(550, 400);
            canvas.BPMNName = "TopLevelCanvas";
            canvas.BPMNShapeType = ShapeType.BPMNTopLevel;
            canvas.BPMNInitialize();

            canvas.Background = Brushes.White;
            canvas.Width = 700;
            canvas.Height = 2000;
            canvas.Background = Brushes.LightGray;
            scrollContainer.Content = canvas;

            TreeViewItem item = new TreeViewItem();
            item.Tag = canvas.BPMNName;
            item.Header = canvas.BPMNName;
            tvBPMNShape.Items.Add(item);
            UpdateTvWithCanvas();

        }

        public void addProperties(BPMNShape obj)
        {
            lvProperties.Items.Clear();
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj, true);
            BPMNPropertyAttribute a = new BPMNPropertyAttribute();
            foreach (PropertyDescriptor prop in props)
            {
                if (prop.Attributes.Contains(a))
                {
                    DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(prop);
                    if (dpd != null)
                    {
                        DependencyProperty dp = dpd.DependencyProperty;
                        if (dp != null)
                        {
                            lvProperties.Items.Add(new BPMNValue(obj, dp));
                        }
                    }
                }
            }
        }

        private void BPMNInitialize()
        {
            (Application.Current as App).BPMNCMShowing += new App.BPMNContextMenuShowing(WindowMain_BPMNCMShowing);

            InitializeCanvas();
            InitializeLeftPanel();
            InitializeRightPanel();
            InitializeBottomPanel();
            InitializeToolbar();
        }

        private void InitializeToolbar()
        {
            tbTip.Content = "Right-click the canvas and select 'New' to add a new shape";
        }

        public void ReceiveNotification(string notification)
        {

            ListViewItem item = new ListViewItem();
            item.Content = notification;
            lvNotifications.Items.Add(item);
            lvNotifications.ScrollIntoView(item);
        }
        private void InitializeRightPanel()
        {
            tvBPMNShape.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(tvBPMNShape_SelectedItemChanged);

        }

        void tvBPMNShape_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            TreeViewItem item = e.NewValue as TreeViewItem;
            BPMNShape s = null;
            FindTVIParent(item, ref s);
            WindowMain.SelectedBPMNShape = s;
        }

        TreeViewItem FindTVIParent(TreeViewItem item, ref BPMNShape s)
        {
            TreeViewItem parentItem;
            if ((item.Parent as TreeViewItem) == null)
            {
                parentItem = item;
                s = canvas;

            }
            else
            {
                parentItem = FindTVIParent(item.Parent as TreeViewItem, ref s);
                for (int i = 0; i < s.Children.Count; i++)
                {
                    BPMNShape sChildren = (s.Children[i] as BPMNShape);
                    if (sChildren != null && sChildren.BPMNName == item.Header)
                    {
                        s = sChildren;
                    }
                }
                parentItem = item;
            }

            return parentItem;
        }


        public void UpdateTvWithCanvas()
        {
            if (tvBPMNShape.Items.Count > 0)
            {
                UpdateBPMNTV(canvas, tvBPMNShape.Items[0] as TreeViewItem);
            }
        }

        public void UpdateBPMNTV(BPMNShape shape, TreeViewItem item)
        {
            if (shape != null)
            {
                item.Header = shape.BPMNName;
                List<string> foundItems = new List<string>();
                for (int i = 0; i < shape.Children.Count; i++)
                {
                    BPMNShape child = shape.Children[i] as BPMNShape;
                    if (child != null)
                    {
                        bool found = false;
                        for (int j = 0; j < item.Items.Count; j++)
                        {
                            TreeViewItem childItem = (item.Items[j] as TreeViewItem);
                            if (childItem != null)
                            {
                                if (child.BPMNName == childItem.Tag.ToString())
                                {
                                    UpdateBPMNTV(child, childItem);
                                    found = true;
                                    foundItems.Add(childItem.Tag.ToString());
                                    if (i != j)
                                    {
                                        TreeViewItem parentTVI = (childItem.Parent as TreeViewItem);
                                        parentTVI.Items.Remove(childItem);
                                        try
                                        {
                                            parentTVI.Items.Insert(i, childItem);
                                        }
                                        catch (Exception e)
                                        {
                                            BPMNException exc = new BPMNException(e, "");
                                        }
                                    }
                                }
                            }
                        }
                        if (!found)
                        {
                            TreeViewItem newItem = new TreeViewItem();
                            newItem.Tag = child.BPMNName;
                            newItem.Header = child.BPMNName;
                            item.IsExpanded = true;
                            item.Items.Add(newItem);
                            foundItems.Add(child.BPMNName);
                            UpdateBPMNTV(child, newItem);
                        }
                    }
                }
                for (int j = 0; j < item.Items.Count; j++)
                {
                    TreeViewItem childItem = (item.Items[j] as TreeViewItem);
                    if (!foundItems.Contains(childItem.Tag.ToString()))
                    {
                        (childItem.Parent as TreeViewItem).Items.Remove(childItem);
                    }
                }
            }
        }


        private void InitializeBottomPanel()
        {

            btnClearNotifications.Click += new RoutedEventHandler(btnClearNotifications_Click);
        }

        void btnClearNotifications_Click(object sender, RoutedEventArgs e)
        {
            lvNotifications.Items.Clear();
        }

        private void InitializeLeftPanel()
        {
            bpmnExpanderBasicShapes = new BPMNExpander("Basic Shapes");
            bpmnExpanderBasicShapes.IsExpanded = true;
            bpmnExpanderBasicShapes.addItem("Pool", null, BasicShapeType.Pool);
            bpmnExpanderBasicShapes.addItem("Lane", null, BasicShapeType.Lane);
            bpmnExpanderBasicShapes.addItem("Activity", null, BasicShapeType.Activity);
            bpmnExpanderBasicShapes.Width = 180;
            pnlLeft.Children.Add(bpmnExpanderBasicShapes);

            bpmnExpanderStartEvents = new BPMNExpander("Start Events");
            bpmnExpanderStartEvents.IsExpanded = true;
            bpmnExpanderStartEvents.addItem("Start Event", null, "None");
            bpmnExpanderStartEvents.addItem("Start Event Message", null, "Message");
            bpmnExpanderStartEvents.addItem("Start Event Timer", null, "Timer");
            bpmnExpanderStartEvents.addItem("Start Event Rule", null, "Rule");
            bpmnExpanderStartEvents.addItem("Start Event Link", null, "Link");
            bpmnExpanderStartEvents.addItem("Start Event Multiple", null, "Multiple");
            bpmnExpanderStartEvents.Width = 180;

            pnlLeft.Children.Add(bpmnExpanderStartEvents);

            bpmnExpanderIntermediateEvents = new BPMNExpander("Intermediate Events");
            bpmnExpanderIntermediateEvents.IsExpanded = true;
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event", null, "None");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Message", null, "Message");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Timer", null, "Timer");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Error", null, "Error");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Cancel", null, "Cancel");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Compensation", null, "Compensation");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Link", null, "Link");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Multiple", null, "Multiple");
            bpmnExpanderIntermediateEvents.addItem("Intermediate Event Rule", null, "Rule");
            bpmnExpanderIntermediateEvents.Width = 180;
            pnlLeft.Children.Add(bpmnExpanderIntermediateEvents);

            bpmnExpanderEndEvents = new BPMNExpander("End Events");
            bpmnExpanderEndEvents.IsExpanded = true;
            bpmnExpanderEndEvents.addItem("End Event", null, "None");
            bpmnExpanderEndEvents.addItem("End Event Message", null, "Message");
            bpmnExpanderEndEvents.addItem("End Event Error", null, "Error");
            bpmnExpanderEndEvents.addItem("End Event Cancel", null, "Cancel");
            bpmnExpanderEndEvents.addItem("End Event Compensation", null, "Compensation");
            bpmnExpanderEndEvents.addItem("End Event Link", null, "Link");
            bpmnExpanderEndEvents.addItem("End Event Multiple", null, "Multiple");
            bpmnExpanderEndEvents.addItem("End Event Terminate", null, "Terminate");
            bpmnExpanderEndEvents.Width = 180;
            pnlLeft.Children.Add(bpmnExpanderEndEvents);

            bpmnExpanderGateways = new BPMNExpander("Gateways");
            bpmnExpanderGateways.IsExpanded = true;
            bpmnExpanderGateways.addItem("BPMNGateway", null, "None");
            bpmnExpanderGateways.addItem("BPMNGateway Databased", null, "XorDatabased");
            bpmnExpanderGateways.addItem("BPMNGateway Eventbased", null, "XorEventbased");
            bpmnExpanderGateways.addItem("BPMNGateway Or", null, "Or");
            bpmnExpanderGateways.addItem("BPMNGateway Complex", null, "Complex");
            bpmnExpanderGateways.addItem("BPMNGateway And", null, "And");
            bpmnExpanderGateways.Width = 180;
            pnlLeft.Children.Add(bpmnExpanderGateways);

            bpmnExpanderConnectingObjects = new BPMNExpander("Connecting Objects");
            bpmnExpanderConnectingObjects.IsExpanded = true;
            bpmnExpanderConnectingObjects.addItem("Sequence Flow", null, "Sequence");
            bpmnExpanderConnectingObjects.addItem("Message Flow", null, "Message");
            bpmnExpanderConnectingObjects.addItem("Association", null, "Association");
            bpmnExpanderConnectingObjects.Width = 180;
            pnlLeft.Children.Add(bpmnExpanderConnectingObjects);

            bpmnExpanderStartEvents.Click += new BPMNExpander.ExpanderButtonClick(bpmnExpandersShapes_Click);
            bpmnExpanderIntermediateEvents.Click += new BPMNExpander.ExpanderButtonClick(bpmnExpandersShapes_Click);
            bpmnExpanderEndEvents.Click += new BPMNExpander.ExpanderButtonClick(bpmnExpandersShapes_Click);
            bpmnExpanderGateways.Click += new BPMNExpander.ExpanderButtonClick(bpmnExpandersShapes_Click);
            bpmnExpanderBasicShapes.Click += new BPMNExpander.ExpanderButtonClick(bpmnExpandersShapes_Click);

            bpmnExpanderConnectingObjects.Click += new BPMNExpander.ExpanderButtonClick(bpmnExpanderConnectingObjects_Click);

        }

        void WindowMain_BPMNCMShowing(object sender, List<string> arguments, ref object refobj)
        {
            if (WindowMain.SelectedBPMNShape != null && !WindowMain.WaitingForUserInteraction)
            {
                WindowMain.AdditionalParameters.Clear();
                switch (arguments[0])
                {
                    case "ConnectNew":
                        tbTip.Content = "Click on the blue area to build a new shape connected with the current one";
                        WindowMain.WaitingForUserInteraction = true;

                        WindowMain.SelectedBPMNShape.ShapeParent.Background = Commons.Utils.BrushCanvasNewShape;
                        WindowMain.SelectedBPMNShape.ShapeParent.Cursor = Cursors.Cross;
                        WindowMain.DrawingToBuild = (ShapeType)Enum.Parse(typeof(ShapeType), arguments[arguments.Count - 2]);
                        WindowMain.AdditionalParameters.Add(arguments[arguments.Count - 1]);
                        ConnectionType connectionType = (ConnectionType)Enum.Parse(typeof(ConnectionType), arguments[arguments.Count - 3]);
                        WindowMain.BPMNConnectingObject = WindowMain.SelectedBPMNShape.CreateConnectionByCommand(connectionType, WindowMain.SelectedBPMNShape);

                        WindowMain.BPMNConnectingObject.FromDrawing = WindowMain.SelectedBPMNShape;
                        WindowMain.SelectedBPMNShape.ShapeParent.MouseUp += new MouseButtonEventHandler(SelectedBPMNShape_CreateNewShapeWithConnection);
                        break;
                    case "New":
                        tbTip.Content = "Click on the blue area to build a new shape";
                        WindowMain.WaitingForUserInteraction = true;
                        WindowMain.SelectedBPMNShape.Background = Commons.Utils.BrushCanvasNewShape;
                        WindowMain.SelectedBPMNShape.Cursor = Cursors.Cross;
                        WindowMain.DrawingToBuild = (ShapeType)Enum.Parse(typeof(ShapeType), arguments[arguments.Count - 2]);
                        WindowMain.AdditionalParameters.Add(arguments[arguments.Count - 1]);
                        WindowMain.SelectedBPMNShape.MouseUp += new MouseButtonEventHandler(SelectedBPMNShape_CreateNewShape);
                        break;
                    case "Locked":
                        WindowMain.SelectedBPMNShape.LockMoving = !WindowMain.SelectedBPMNShape.LockMoving;
                        break;
                    case "Delete":
                        WindowMain.SelectedBPMNShape.Delete();
                        UpdateTvWithCanvas();
                        break;
                    case "SendToBack":
                        WindowMain.selectedBPMNShape.SendToBack();
                        UpdateTvWithCanvas();
                        break;
                    case "BringToFront":
                        WindowMain.selectedBPMNShape.BringToFront();
                        UpdateTvWithCanvas();
                        break;
                }
            }
            else
            {
                BPMNException exc = new BPMNException(null, "Another action pending for this shape");
            }
        }

        void SelectedBPMNShape_CreateNewShape(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left)
            {
                BPMNShape s = WindowMain.SelectedBPMNShape.CreateNewDrawing(e);
                WindowMain.SelectedBPMNShape.MouseUp -= new MouseButtonEventHandler(SelectedBPMNShape_CreateNewShape);
                WindowMain.SelectedBPMNShape.Background = WindowMain.SelectedBPMNShape.DefaultBackground;
                WindowMain.SelectedBPMNShape.Cursor = Cursors.Arrow;
                WindowMain.WaitingForUserInteraction = false;
                if (s != null)
                {
                    UpdateTvWithCanvas();
                }
            }
        }

        void SelectedBPMNShape_CreateNewShapeWithConnection(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left)
            {
                BPMNShape s = WindowMain.SelectedBPMNShape.CreateNewDrawing(e);
                WindowMain.SelectedBPMNShape.MouseUp -= new MouseButtonEventHandler(SelectedBPMNShape_CreateNewShapeWithConnection);
                WindowMain.SelectedBPMNShape.Background = WindowMain.SelectedBPMNShape.DefaultBackground;
                WindowMain.SelectedBPMNShape.Cursor = Cursors.Arrow;
                WindowMain.WaitingForUserInteraction = false;
                if (s != null)
                {
                    UpdateTvWithCanvas();
                    WindowMain.BPMNConnectingObject.ToDrawing = s;
                    WindowMain.selectedBPMNShape.Children.Add(WindowMain.BPMNConnectingObject);
                    WindowMain.BPMNConnectingObject.UpdateLocation();
                    WindowMain.BPMNConnectingObject = null;
                }
            }
        }

        void bpmnExpanderConnectingObjects_Click(object sender)
        {

        }

        void bpmnExpandersShapes_Click(object sender)
        {
            string className = (sender as Control).Tag.ToString();
            DrawingToBuild = (ShapeType)Enum.Parse(typeof(ShapeType), className);
        }
    }
}